//
// Ishtar C++ Utility Library
//
// Task Facility - Worker Thread Implementation
//

#include <Ishtar/Pch.h>

#include <Ishtar/Task/WorkerThreadImpl.h>


namespace Ishtar
{

namespace Task
{

///////////////////////////////////////////////////////////////////////////////
//
// Worker Thread
//

WorkerThreadImpl::WorkerThreadImpl()
    : m_shutdown( false )
{}


void WorkerThreadImpl::Startup( const std::string& name )
{
    m_name = name;
    this->Start();
}


void WorkerThreadImpl::Shutdown()
{
    {
        SpinMutex::UniqueLock ulock( m_addReadyMutex );
        m_shutdown = true;
    }

    m_readyWorks.Stop();

    const Bool ok = m_readyWorks.TimedWaitEmpty( DEFAULT_TIMEOUT );
    if ( !ok )
    {
        std::vector< WorkImplPtr > works;
        m_readyWorks.PopAll( works );

        if ( !works.empty() )
        {
            {
                ISHTAR_TRACE_WARN_HERE( "Shutdown timeout, some works not run" );
                ISHTAR_TRACE_INFO( "  name: %s, numWorks: %u", m_name, works.size() );
            }

            for ( Uint i = 0; i < works.size(); ++ i )
            {
                works[i]->Cancel();
            }
        }
    }

    ISHTAR_ASSERT( m_readyWorks.IsEmpty() );

    this->Join();
}


Int WorkerThreadImpl::Execute()
{
    for ( ;; )
    {
        WorkImplPtr work;

        if ( m_readyWorks.WaitPop( work ))
        {
            work->Run();
        }
        else
            break;
    }

    return EXECUTE_EXIT;
}


void WorkerThreadImpl::Submit( const WorkImplPtr& w )
{
    if ( m_shutdown )
    {
        {
            ISHTAR_TRACE_WARN_HERE( "Thread has been shutdown" );
            ISHTAR_TRACE_INFO( "  threadName: %s, workName: %s", m_name, w->Name() );
        }

        w->Cancel();
        return;
    }

    w->Start( this );
}


void WorkerThreadImpl::AddReadyWork( const WorkImplPtr& w )
{
    {
        SpinMutex::UniqueLock ulock( m_addReadyMutex );

        if ( !m_shutdown )
        {
            m_readyWorks.Push( w );
            return;
        }
    }

    // this thread has been shutdown ...

    {
        ISHTAR_TRACE_WARN_HERE( "Thread has been shutdown" );
        ISHTAR_TRACE_INFO( "  threadName: %s, workName: %s", m_name, w->Name() );
    }

    w->Cancel();
}


//
// Bridging
//

WorkerThread::WorkerThread()
    : m_impl( new WorkerThreadImpl )
{}


WorkerThread::~WorkerThread()
{}


void WorkerThread::Startup( const std::string& name )
{
    m_impl->Startup( name );
}


void WorkerThread::Shutdown()
{
    m_impl->Shutdown();
}


void WorkerThread::Submit( const Work& w )
{
    if ( w.IsEmpty() ) { return; }
    
    m_impl->Submit( w.m_impl );    
}


Uint WorkerThread::GetNumWorks() const
{
    return m_impl->GetNumWorks();
}


Uint WorkerThread::GetNumReadyWorks() const
{
    return m_impl->GetNumReadyWorks();
}


///////////////////////////////////////////////////////////////////////////////

} // namespace Task

} // namespace Ishtar
